Skip to content

Fix parsing CSS selectors which contain commas #138

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed

Conversation

westonruter
Copy link
Collaborator

I found an issue where a CSS selectors would fail to parse correctly when they contain commas. For example:

.widget:not(.widget_text, .jetpack_widget_social_icons) ul {
    list-style: none;
    margin: 0;
    padding: 0;
}

There should only be one selector here: .widget:not(.widget_text, .jetpack_widget_social_icons) ul. Instead, the parser incorrectly extracts two:

  • .widget:not(.widget_text
  • .jetpack_widget_social_icons) ul

The fix is to add placeholders for expressions contained in parentheses or brackets prior to splitting, and then replace the placeholders with their original values on the split selectors.

@westonruter
Copy link
Collaborator Author

@sabberworm Anything else you'd like to see with this PR?

@sabberworm
Copy link
Collaborator

sabberworm commented Sep 3, 2018

Thanks for the input @westonruter. Sorry for the long response time, I had been away on holiday.

While this does solve one of the long-standing gripes I’ve had with selector parsing, it does not solve all of them and I don’t think it’s a particularly elegant solution and it’s not the direction I want to pursue.

What I would like to see is to see the Selector class expanded to becomes an interface with subclasses for every type of (combining) selector there is, so that every selector is stored as an instance instead of a string.

So the selector .a + :not(#b) + [c] ~ foo|.d span > *:root, would decompose into:

new AdjacentSiblingCombinator(
	new ClassSelector('a'),
	new Negation(
		new IDSelector('b')
	),
	new GeneralSiblingCombinator(
		new AttributeSelector('c'),
		new DescendantCombinator(
			new NamespaceSelector(
				'foo',
				new ClassSelector('d')
			),
			new ChildCombinator(
				new TypeSelector('span'),
				new Combinator(
					new UniversalSelector(),
					new RootSelector()
				)
			)
		)
	)
);

Note: this is just a suggestion. Maybe the Combinator could be replaced with a simple array and maybe it’s not a good idea to let the same combinator have more than two elements (like the AdjacentSiblingCombinator in my example, which could instead be transformed into two nested ones). And maybe we don’t need to nest them, just store combinator and simple selector in an array side-by-side.

However what this requires is actually parsing and understanding the selector. And I think string substitution, even when done right, is a poor substitute (pun intended) for that.

Actually parsing selectors would finally also fix the following:

.some[selectors-may='contain-a-{'] {}

which parses neither with nor without your fix.

@westonruter
Copy link
Collaborator Author

Thanks. You're right. My fix is more of a bandaid than a permanent solution. I wasn't sure that you intended to actually have the selector themselves parsed as well. That being the case, then indeed my fix isn't ideal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants